不知道大家有沒有在日本看過電視呢?在日本,放送的信號裡頭有許多資訊,包含節目時間表、電視影像(還可以切換解析度)、字幕等等。所以在電視裡頭可以開啟與關閉字幕。
那麼實際上到底是怎麼運作的呢?今天就來聊聊有關於日本電視放送的字幕解析。
會開始研究這部分的技術,是因為謙謙之前的推文,再加上之前就想要試試看能不能夠用 tuner 接電腦來看電視,意外發現裡頭有許多技術細節很值得學習。
日本的電視放送是由日本自主制定的協定,叫做 ISDB(Integrated Services Digital Broadcasting),透過無線基地台發送信號,各個家庭接收到電視信號之後,在解密並復原成原始資料。
日本的電視信號為了防止無限地被複製及保護版權,其實是有先經過加密才發送出來的。這部分被規範在 ARIB(STD-B25)裏頭。而 B-CAS 就像是一把鑰匙,必須要有這張卡片才能看電視。如果有在日本買過電視的話,買電視的時候通常會附上這張 B-CAS 卡一起賣,否則是沒辦法看到影像的。
廣播電台會和願意遵守複製規範的廠商簽約,並直接將密鑰訊息給這些廠商,廠商再去製作已經含有金鑰的硬體,例如現在很多 USB 型的調解器,只要插進去電腦就可以接收信號並看電視。然而這類型的調解器通常需要下載他們專用的播放器才能正常瀏覽。原因就是因為要防止隨意複製。
MPEG2-TS 是一種影片的封裝格式,日本的放送傳輸通常都是使用 MPEG2-TS。這邊的 TS 全稱是 Transport Stream。視訊通常是用 h.262 編碼;音訊則是用 AAC 編碼。h.262
由於比較舊,所以同樣的影片編碼,大小會比較大。一般我們在電腦上看影片 .mp4
通常都是用 h.264 在編碼。
在封包傳送上,每個 TS 封包最大為 188bytes。在無線傳輸時可能會有雜訊、錯誤,188bytes 大小不大,可以減少延遲,同時也比較容易做錯誤復原。
TS 封包的各種敘述可以參考這張圖。
其中幾個比較重要的欄位有幾個:
0x47
關於放送的技術細節雖然有很多地方可以研究,不過礙於篇幅關係,我們只專注在解析字幕的部分。字幕的解析與傳送是由 ARIB-B24 所規範。
大致上的過程如下:
0x47
一個 caption data 除了「文字的訊息」之外,其實還包含了很多資訊,像是顏色、形狀、字幕應該要表示的位置等等,這些資料會透過 data unit 來區分。而文字訊息的 data unit 為 0x20
。
function parseText(data, length) {
const str = data.slice(0, length + 1);
let result = '';
let i = 0;
while (i < length) {
if (str[i] === 0x20) {
result += ' ';
i += 1;
}
// // JIS X 0208 (lead bytes)
if (str[i] > 0xa0 && str[i] < 0xff) {
const char = str.slice(i, i + 2);
if (str[i] >= 0xfa) {
result += parseGaiji(char);
i += 2;
} else {
const decoded = new TextDecoder('EUC-JP').decode(char);
result += decoded;
i += 2;
}
} else if (Object.values(JIS_CONTROL_FUNCTION_TABLE).includes(str[i])) {
console.log('JIS_CONTROL_TABLE!');
i += 1;
} else if (str[i] >= 0x80 && str[i] <= 0x87) {
console.log('color map');
i += 1;
} else {
i += 1;
}
}
console.log(result);
document.querySelector('#result').innerHTML += result + '<br/>';
}
由於這邊的文字是用 JIS-0208 的字集,所以要另外解碼。不過在 JavaScript 中可以使用 TextDecoder,剛好也有支援 EUC-JP
,因此直接使用 new TextDecoder('EUC-JP').decode
即可。
另外在日文表示當中還有所謂的「外字」,是 ARIB 定義的,並不存在於 JIS-0208 的文字。主要用來顯示資訊,或是播放跑馬燈等等。詳細可以參考維基百科
這類型的文字就必須另外去解析。成功解析字幕之後,最重要的是要如何在正確的時間點顯示在螢幕上,在信號傳輸的時候會傳送一個 time table 用來對時。
由於沒辦法直接將影片資料上傳的原因,這邊只能給大家看程式碼與截圖,如果有興趣的話可以自行實作看看。
由於是使用 h.262 編碼,因此對大部分瀏覽器來說都不支援,如果要在網頁上看的話,要嘛是用 WebAssembly 去軟解 h.262,但是這樣會非常吃 CPU 的效能,還沒看影片就要先下載一大坨 WASM,用來玩玩還好但實際使用者體驗會非常糟。因此大部分的情況下需要另外用 ffmpeg 等工具將 h.262 改為 h.264 才能在網頁上播放。
目前比較有名的開源方案是 mirakurun,原理是起一個伺服器然後不斷地將放送信號改為 h.264 回傳,這樣一來就算在瀏覽器也能直接觀看。
除此之外,也有一些開源方案可供參考:
就算只是顯示字幕,背後仍然有許多技術細節值得學習,這次實作的過程中也學習到很多東西,像是我原本不知道 MPEG-TS 的格式;也完全不知道 ARIB、ISDB-T 的存在,但其實這些協定已經支撐著日本放送很多年了。
實際操作之後也會發現並不像想像中的那麼難(單就字幕解析而言,復元原始信號那邊我完全不懂),只要耐著性子看文件也可以實作出來。